<template>
  <div class="mark-line">
    <div
      v-for="line in lines"
      v-show="lineStatus[line] || false"
      :key="line"
      :ref="line"
      class="line"
      :class="line.includes('x') ? 'xline' : 'yline'"
      :style="line.includes('x') ? { height: `${1 / scaleRatio}px` } : { width: `${1 / scaleRatio}px` }"
    ></div>
  </div>
</template>

<script>
  import { mapGetters, mapMutations } from 'vuex';

  export default {
    data() {
      return {
        lines: ['xt', 'xc', 'xb', 'yl', 'yc', 'yr'], // 分别对应三条横线和三条竖线
        lineStatus: {
          xt: false,
          xc: false,
          xb: false,
          yl: false,
          yc: false,
          yr: false
        }
      };
    },

    computed: {
      ...mapGetters('component', ['activeComponent', 'componentData', 'previewer', 'scaleRatio']),
      diff() {
        return 3;
      } // 相距 dff 像素将自动吸附
    },

    mounted() {
      // 监听元素移动和不移动的事件
      this.$EventBus.$on('hook:move', (isDownward, isRightward) => {
        this.showLine(isDownward, isRightward);
      });

      this.$EventBus.$on('hook:unmove', () => this.hideLine());
    },

    beforeDestroy() {
      this.$EventBus.$off('hook:unmove');
    },

    methods: {
      ...mapMutations('component', ['SET_ACTIVECOMPOENNT_STYLE']),

      hideLine() {
        Object.keys(this.lineStatus).forEach((line) => {
          this.lineStatus[line] = false;
        });
      },

      showLine(isDownward, isRightward) {
        const lines = this.$refs;
        const components = this.componentData;
        const activeComponentStyle = this.activeComponent.style;
        const activeComponentStyleRight = activeComponentStyle.left + activeComponentStyle.width;
        const activeComponentStyleBottom = activeComponentStyle.top + activeComponentStyle.height;
        const activeComponentHalfWidth = activeComponentStyle.width / 2;
        const activeComponentHalfHeight = activeComponentStyle.height / 2;

        this.hideLine();
        components.forEach((component) => {
          // if (component == this.activeComponent) return;
          const componentStyle = component.style;
          const { top, left } = componentStyle;
          const right = componentStyle.left + componentStyle.width;
          const bottom = componentStyle.top + componentStyle.height;
          const componentHalfWidth = componentStyle.width / 2;
          const componentHalfHeight = componentStyle.height / 2;
          const previewerHeight = this.previewer.height;

          let conditions = {
            top: [
              {
                isNearly: this.isNearly(activeComponentStyle.top, 0),
                lineNode: lines.xt[0], // xt
                line: 'xt',
                dragShift: 0,
                lineShift: 0
              },
              {
                isNearly: this.isNearly(activeComponentStyleBottom, previewerHeight),
                lineNode: lines.xb[0], // xb
                line: 'xb',
                dragShift: previewerHeight - activeComponentStyle.height,
                lineShift: previewerHeight
              }
            ],
            left: [
              // {
              //   isNearly: this.isNearly(activeComponentStyle.left, 0),
              //   lineNode: lines.yl[0], // yl
              //   line: 'yl',
              //   dragShift: 0,
              //   lineShift: 0
              // },
              // {
              //   isNearly: this.isNearly(activeComponentStyle.left + activeComponentHalfWidth, 187.5),
              //   lineNode: lines.yc[0], // yc
              //   line: "yc",
              //   dragShift: 187.5 - activeComponentHalfWidth,
              //   lineShift: 187.5
              // },
              // {
              //   isNearly: this.isNearly(activeComponentStyleRight, 375),
              //   lineNode: lines.yr[0], // yr
              //   line: 'yr',
              //   dragShift: 375 - activeComponentStyle.width,
              //   lineShift: 375
              // }
            ]
          };
          if (component !== this.activeComponent)
            conditions = {
              top: [
                {
                  isNearly: this.isNearly(activeComponentStyle.top, top),
                  lineNode: lines.xt[0], // xt
                  line: 'xt',
                  dragShift: top,
                  lineShift: top
                },
                {
                  isNearly: this.isNearly(activeComponentStyleBottom, top),
                  lineNode: lines.xt[0], // xt
                  line: 'xt',
                  dragShift: top - activeComponentStyle.height,
                  lineShift: top
                },
                {
                  // 组件与拖拽节点的中间是否对齐
                  isNearly: this.isNearly(
                    activeComponentStyle.top + activeComponentHalfHeight,
                    top + componentHalfHeight
                  ),
                  lineNode: lines.xc[0], // xc
                  line: 'xc',
                  dragShift: top + componentHalfHeight - activeComponentHalfHeight,
                  lineShift: top + componentHalfHeight
                },
                {
                  isNearly: this.isNearly(activeComponentStyle.top, bottom),
                  lineNode: lines.xb[0], // xb
                  line: 'xb',
                  dragShift: bottom,
                  lineShift: bottom
                },
                {
                  isNearly: this.isNearly(activeComponentStyleBottom, bottom),
                  lineNode: lines.xb[0], // xb
                  line: 'xb',
                  dragShift: bottom - activeComponentStyle.height,
                  lineShift: bottom
                },
                ...conditions.top
              ],
              left: [
                {
                  isNearly: this.isNearly(activeComponentStyle.left, left),
                  lineNode: lines.yl[0], // yl
                  line: 'yl',
                  dragShift: left,
                  lineShift: left
                },
                {
                  isNearly: this.isNearly(activeComponentStyleRight, left),
                  lineNode: lines.yl[0], // yl
                  line: 'yl',
                  dragShift: left - activeComponentStyle.width,
                  lineShift: left
                },
                {
                  // 组件与拖拽节点的中间是否对齐
                  isNearly: this.isNearly(
                    activeComponentStyle.left + activeComponentHalfWidth,
                    left + componentHalfWidth
                  ),
                  lineNode: lines.yc[0], // yc
                  line: 'yc',
                  dragShift: left + componentHalfWidth - activeComponentHalfWidth,
                  lineShift: left + componentHalfWidth
                },
                {
                  isNearly: this.isNearly(activeComponentStyle.left, right),
                  lineNode: lines.yr[0], // yr
                  line: 'yr',
                  dragShift: right,
                  lineShift: right
                },
                {
                  isNearly: this.isNearly(activeComponentStyleRight, right),
                  lineNode: lines.yr[0], // yr
                  line: 'yr',
                  dragShift: right - activeComponentStyle.width,
                  lineShift: right
                },
                ...conditions.left
              ]
            };

          const needToShow = [];
          Object.keys(conditions).forEach((key) => {
            // 遍历符合的条件并处理
            conditions[key].some((condition) => {
              if (!condition.lineNode) return false;
              if (!condition.isNearly) return false;
              // 修改当前组件位移
              this.SET_ACTIVECOMPOENNT_STYLE({
                key,
                value: condition.dragShift
              });
              condition.lineNode.style[key] = `${condition.lineShift}px`;
              needToShow.push(condition.line);
              return true;
            });
          });
          // 同一方向上同时显示三条线可能不太美观，因此才有了这个解决方案
          // 同一方向上的线只显示一条，例如多条横条只显示一条横线
          if (needToShow.length) {
            this.chooseTheTureLine(needToShow, isDownward, isRightward);
          }
        });
      },

      chooseTheTureLine(needToShow, isDownward, isRightward) {
        // 如果鼠标向右移动 则按从右到左的顺序显示竖线 否则按相反顺序显示
        // 如果鼠标向下移动 则按从下到上的顺序显示横线 否则按相反顺序显示
        if (isRightward) {
          if (needToShow.includes('yr')) {
            this.lineStatus.yr = true;
          } else if (needToShow.includes('yc')) {
            this.lineStatus.yc = true;
          } else if (needToShow.includes('yl')) {
            this.lineStatus.yl = true;
          }
        } else {
          if (needToShow.includes('yl')) {
            this.lineStatus.yl = true;
          } else if (needToShow.includes('yc')) {
            this.lineStatus.yc = true;
          } else if (needToShow.includes('yr')) {
            this.lineStatus.yr = true;
          }
        }

        if (isDownward) {
          if (needToShow.includes('xb')) {
            this.lineStatus.xb = true;
          } else if (needToShow.includes('xc')) {
            this.lineStatus.xc = true;
          } else if (needToShow.includes('xt')) {
            this.lineStatus.xt = true;
          }
        } else {
          if (needToShow.includes('xt')) {
            this.lineStatus.xt = true;
          } else if (needToShow.includes('xc')) {
            this.lineStatus.xc = true;
          } else if (needToShow.includes('xb')) {
            this.lineStatus.xb = true;
          }
        }
      },

      isNearly(dragValue, targetValue) {
        if (dragValue === targetValue) return false;
        return Math.abs(dragValue - targetValue) <= this.diff;
      }
    }
  };
</script>

<style lang="scss" scoped>
  .mark-line {
    // position: absolute;
    // top: 0;
    // left: 0;
    // width: 100%;
    // height: 100%;
    width: 0;
    height: 0;
    // z-index: -1;
  }

  .line {
    position: absolute;
    z-index: 999;
    height: 100%;
    background: map-get($bgColors, 'theme');
  }

  .xline {
    left: 0;
    width: 100%;
    height: 1px;
  }

  .yline {
    top: 0;
    width: 1px;
    height: 100%;
  }
</style>
